// builtins table

static builtin_entry builtin_commands[] = {
   { {3,'d','u','p'},               &_dup             },
   { {4,'d','r','o','p'},           &_drop            },
   { {5,'c','l','e','a','r'},       &_clear           },
   { {4,'s','w','a','p'},           &_swap            },
   { {4,'o','v','e','r'},           &_over            },
   { {5,'d','e','p','t','h'},       &_depth           },

   { {6,'l','a','m','b','d','a'},   &_lambda   },
   { {5,'t','a','b','l','e'},       &_table    },

   { {5,'s','t','a','c','k'},       &_stack           },
   { {5,'p','r','i','n','t'},       &_print           },
   { {4,'q','u','i','t'},           &_quit            },

   { {0}, NULL }
};

// builtin functions:

BUILTIN(_dup) {
   if (!stack)
      return _warning("DUP" INSUFFICIENT_ARGS_STK);
   Atom *a = duplicate_atom(stack->head);
   return a;
}

BUILTIN(_drop) {
   if (!stack)
      return _warning("DROP" INSUFFICIENT_ARGS_STK);
   stack_pop(1, &stack);
   return NULL;
}

BUILTIN(_clear) {
   if (!stack)
      return _warning("CLEAR" EMPTY_STACK);
   stack_pop(0, &stack);
   return NULL;
}

BUILTIN(_swap) {
   if (!stack || !stack->tail)
      return _warning("SWAP" INSUFFICIENT_ARGS_STK);
   Atom *a = stack->head;
   stack->head = stack->tail->head;
   stack->tail->head = a;
   return NULL;
}

BUILTIN(_over) {
   if (!stack || !stack->tail)
      return _warning("OVER" INSUFFICIENT_ARGS_STK);
   return duplicate_atom(stack->tail->head);
}

BUILTIN(_depth) {
   Atom *a = create_int(0);
   a->num = list_size(stack);
   return a;
}

BUILTIN(_print) {
   if (!li) {
      if (!stack)
         return _warning("PRINT" INSUFFICIENT_ARGS_STK);
      print_expression(stack->head);
      putchar(10);
      return NULL;
   }
   while (li) {
      print_expression(li->head);
      if (li->tail)
         putchar(' ');
      li = li->tail;
   }
   putchar(10);
   return NULL;
}

BUILTIN(_stack) {
   if (!stack) return _warning("STACK: <Empty>");
   printf("STACK: ");
   _print(stack, ctx);
   return NULL;
}

BUILTIN(_lambda) {
   if (li) {
      if (!valid_lambda(li))
         return _warning("LAMBDA" INVALID_ARGS);
      return create_lambda(duplicate_list(li));
   }
   if (!stack || !stack->head) return _warning("LAMBDA" INSUFFICIENT_ARGS_STK);
   if (!is_list(stack->head)) return _warning("LAMBDA" INVALID_ARGS_STK);
   if (!valid_lambda(stack->head->list)) return _warning("LAMBDA" INVALID_ARGS_STK);
   return create_lambda(duplicate_list(stack->head->list));
}

BUILTIN(_table) {
   #warning TODO
   return NULL;
}

BUILTIN(_quit) {
   #warning TODO
   puts("Quitting...");
   interrupted = 1;
   return NULL;
}
